/***************************************************************
 * FILENAME:  LAB4.c
 *
 * CREATED: 10/15/2012 7:27:58 PM
 * AUTHOR:    zimmermane@msoe.edu <Evan Zimmerman>
 *            duerk@msoe.edu <Kevin Duer>
 * PROVIDES:  a driver for the whole program
**************************************************************/

#include <avr/io.h>        //to use named components on Atmega 32
#include <avr/interrupt.h> //will include the interrupt vectors
#include <stdbool.h>       //for boolean
#include <stdio.h>		   //for I/O functions
#include <string.h>		   //for the String class
#include <avr/sleep.h>	   //For the Avr sleep functions
#include "lcd3200.h"
#include "usart3200.h"
#include "helpers.h"
#include "adc3200.h"

// LCD update types
typedef enum LCDCommand {HEARTBEAT, TEMPERATURE} updateType;

static volatile bool heart;       //indicates whether the heart is on or off
static volatile bool update_heartBeat;   //used to indicate time to update heart icon
static volatile bool update_temp;   //used to indicate time to update temperature
static volatile bool sleep_enabled;    //used to enable the sleep function
static volatile char sleep_counter;
static volatile char temp_counter;

static volatile char adcVal;  // raw ADC value
static volatile char tempF; // temp in Fahrenheit
static volatile char tempC; // temp in Celsius


// set up a file stream which will allow us to use printf to call our lcd_send_data method
FILE lcd_str = FDEV_SETUP_STREAM(lcd_send_data, lcd_send_data, _FDEV_SETUP_RW);


/*
 * display_welcome
 * Purpose: To display the welcome screen on the LCD
 * Parameters: None
 * Returns: None
 */
void display_welcome(void){
	lcd_send_data(0x11); // make sure backlight is on
	lcd_send_data(0x0C); // clear the screen
	delay_ms(60);
	lcd_gotoxy(0,0);
	printf("CE3200 ZIGBEE");
	lcd_gotoxy(1,0);
	printf("WELCOME!");
}

void LCD_UPDATE(updateType command){
	lcd_send_data(0x11); // make sure backlight is on
	switch (command)
	{
		case HEARTBEAT:
			lcd_gotoxy(0,15);
			if(heart){
				heart = false;
				lcd_send_data(' ');	
			}
			else{
				heart = true;
				lcd_send_data('H');
			}				
			break;
		case TEMPERATURE:
			lcd_gotoxy(0,0);
			printf("%u F           ",tempF); // degrees Fahrenheit
			lcd_gotoxy(1,0);
			printf("%u C           ",tempC); // degrees Celsius
			break;
	}
}

/*
 * main
 * Purpose: This will be the method which controls the whole system
 *			it will setup default values and enter into a forever
 *			loop to check set values
 * Parameters: None
 * Returns: None
 */
int main(void){
	
	//setup default values
	heart = false;
	update_heartBeat = true;
	update_temp = true;
	sleep_enabled = false;
	sleep_counter = 0; // count to 240 interrupts for 2 minutes of system sleep
	temp_counter = 0;  // count to 10 interrupts for 5 seconds of temp display
	adcVal = 0;
	tempF = 0;
	tempC = 0;
	
	stdin = stdout = &lcd_str;
	
	// setup timer1A to interrupt every 500ms
	OCR1A = 0x1E85; // 7813
	
	//start counting at 0
	TCNT1H = 0;
	TCNT1L = 0;
	
	//set Timer counter 1 Output Compare for interrupt
	TIMSK = (1<<OCIE1A);
	
	//initialize needed peripherals
	adc_init(1);       // initialize ADC on ADC0 (PINA0)
	usart_init();      // initialize the USART
	lcd_init();        // initialize the LCD
	display_welcome(); // display welcome screen for
	                   // 3 seconds at startup
	delay_ms(3000);
	
	// initialize tccr1b: CTC mode, clk/1024 (starts the timer)
	TCCR1B = (1<<WGM12) | (1<<CS12) | (1<<CS10);
	
	// set the sleep mode to IDLE on sleep
	set_sleep_mode(SLEEP_MODE_IDLE);
	
	//Enable global interrupts
	sei();
	
	//forever loop to update and track program
	while(true){
		
		if(update_heartBeat){
			update_heartBeat = false;
			LCD_UPDATE(HEARTBEAT);
		}
		
		if(update_temp){
			update_temp = false;
			adc_start();
			adc_wait(); // wait here for conversion to finish (polling)
			adcVal = get_adcl(); // the temp will fit completely in ADCL
			get_adch(); // We have to read ADCH to unlock the registers even if its not needed
			
			// Fahrenheit = ADCval/2
			tempF = (adcVal>>1); 
			
			// Celsius = (Fahrenheit - 32) / 1.8
			// for sake of not using floating point numbers (slow), we will say the division is by 2
			tempC = ((tempF-32)>>1); 
			
			LCD_UPDATE(TEMPERATURE);
		}
		
		cli();
		if(sleep_enabled){
			lcd_send_data(0x12); // make sure backlight is off
			// start the system sleep
			sleep_enable();
			sei();
			sleep_cpu();
		}
		else
			sleep_disable();
			
		sei();		
    }
}

/* 
 * TIMER1_COMPA_vect
 * Purpose: Handles sleep time and heartbeat and temperature updates
 */
ISR(TIMER1_COMPA_vect){
	
	if(sleep_enabled){
		sleep_counter++; // count to 240 for 2 minutes of sleep
		//if (sleep_counter == 240)
		if (sleep_counter == 10)
		{
			sleep_counter = 0;
			sleep_enabled = false;
			update_temp = true;
		}
	}

	if (!sleep_enabled){
		temp_counter++; // count to 10 for 5 seconds of temp display
		if(temp_counter == 10){
			temp_counter = 0;
			sleep_enabled = true;
		}
		else
			update_heartBeat = true; // update heartbeat every 500ms
	}
	
}